package main

import (
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"time"

	"github.com/gorilla/websocket"
	"github.com/hpcloud/tail"
	_ "github.com/mattn/go-sqlite3"
)

func IndexHandler(w http.ResponseWriter, r *http.Request) {
	temp, err := template.ParseFiles("./index.html")
	if err != nil {
		log.Panicln(err.Error())
	}
	temp.Execute(w, nil)
}

func InfoHandler(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()
	if r.Method == "GET" {
		var get_error error
		var jsonInfo JOBINFO
		data, err := jsonInfo.select_all_row()
		if err != nil {
			get_error = err
			goto get_return_label
		}
	get_return_label:
		if get_error != nil {
			ERROR_202(w, get_error.Error())
		} else {
			ERROR_200(w, data)
		}
		return
	} else if r.Method == "DELETE" {
		var delete_err error
		defer r.Body.Close()
		jsonInfo := &JOBINFO{}
		if err := jsonInfo.expose_data(r); err != nil {
			delete_err = err
			goto delete_return_label
		}
		if err := jsonInfo.delete_row(); err != nil {
			delete_err = err
			goto delete_return_label
		}

		//todo删除json文件，删除日志
		_ = os.Remove("./job/" + jsonInfo.Uuid + "_" + jsonInfo.Name + ".json")
		_ = os.Remove("./log/addax_" + jsonInfo.Uuid + "_" + jsonInfo.Name + ".json.log")
	delete_return_label:
		if delete_err != nil {
			ERROR_202(w, delete_err.Error())
		} else {
			ERROR_200(w, jsonInfo.Uuid)
		}

		return
	} else if r.Method == "PUT" {
		var put_err error
		defer r.Body.Close()
		jsonInfo := &JOBINFO{}
		if err := jsonInfo.expose_data(r); err != nil {
			put_err = err
			goto put_return_label
		}
		//任务状态 0 新建 1运行 2成功 3报错
		go func() {
			log.Printf("任务开始执行: %s \n", jsonInfo.Uuid)
			//更改状态为运行
			if err := jsonInfo.start_row(1); err != nil {
				log.Println(err.Error())
			}
			if !checkFileIsExist("./job/" + jsonInfo.Uuid + "_" + jsonInfo.Name + ".json") {
				err := ioutil.WriteFile("./job/"+jsonInfo.Uuid+"_"+jsonInfo.Name+".json", []byte(jsonInfo.Json), 0777)
				if err != nil {
					log.Println(err)
					return
				}
			}
			cmd := exec.Command("bash", "./bin/addax.sh", "./job/"+jsonInfo.Uuid+"_"+jsonInfo.Name+".json")
			err := cmd.Run()
			if err != nil {
				log.Println(err.Error())
				//更改状态为运行失败
				if err = jsonInfo.start_row(3); err != nil {
					log.Println(err.Error())
				}
				return
			}
			//更改状态为运行成功
			if err = jsonInfo.start_row(2); err != nil {
				log.Println(err.Error())
			}
			log.Println("程序顺利执行完成，更改任务状态")
		}()

	put_return_label:
		if put_err != nil {
			ERROR_202(w, put_err.Error())
		} else {
			ERROR_200(w, jsonInfo.Uuid)
		}
		return
	}
}
func JobHandler(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()
	var job_err error
	jsonInfo := &JOBINFO{}
	if err := jsonInfo.expose_data(r); err != nil {
		job_err = err
		goto job_return_label
	}

	if err := jsonInfo.create_job_json(); err != nil {
		job_err = err
		goto job_return_label
	}

	if err := jsonInfo.insert_row(); err != nil {
		job_err = err
		goto job_return_label
	}
job_return_label:
	if job_err != nil {
		ERROR_202(w, job_err.Error())
	} else {
		ERROR_200(w, jsonInfo.Uuid)
	}
	return
}
func WsWriter(ws *websocket.Conn, filename string) {
	seek := &tail.SeekInfo{}
	seek.Offset = 0
	seek.Whence = os.SEEK_CUR
	config := tail.Config{}
	config.ReOpen = true
	config.Follow = true
	config.Location = seek
	config.MustExist = false
	config.Poll = true
	t, err := tail.TailFile("./log/addax_"+filename, config)
	if err != nil {
		log.Println("Tail file error")
		return
	}
	old_file_offset := t.Config.Location.Offset
	pingTircker := time.NewTicker(30 * time.Second)
	fileCheckTircker := time.NewTicker(30 * time.Second)
	defer func() {
		pingTircker.Stop()
		t.Stop()
		ws.Close()
	}()
	for {
		select {
		case <-fileCheckTircker.C:
			log.Println("检查socket时间段")
			if old_file_offset != t.Config.Location.Offset {
				old_file_offset = t.Config.Location.Offset
			} else {
				//超过30s没有更新数据那么退出socket
				return
			}
		case msg, ok := <-t.Lines:
			if !ok {
				log.Println("tail file end")
				return
			}
			//for debug
			log.Println(msg.Text)
			//3秒后断开
			ws.SetWriteDeadline(time.Now().Add(3 * time.Second))
			if err := ws.WriteMessage(websocket.TextMessage, []byte(msg.Text)); err != nil {
				log.Println(err.Error())
				log.Println("ws 写数据时出现问题 , 退出关闭")
				return
			}
			//连接保持
		case <-pingTircker.C:
			//3秒后断开
			ws.SetWriteDeadline(time.Now().Add(3 * time.Second))
			if err := ws.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
				log.Println(err.Error())
				log.Println("ws 在发送心跳时出现问题 , 退出关闭")
				return
			}
		}
	}

}

func WsHandler(w http.ResponseWriter, r *http.Request) {
	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		if _, ok := err.(websocket.HandshakeError); !ok {
			log.Println(err)
		}
	}
	go WsWriter(ws, r.URL.Query().Get("filename"))
}

func main() {
	INIT()

	http.Handle("/js/", http.FileServer(http.Dir("./")))
	http.HandleFunc("/", IndexHandler)
	http.HandleFunc("/job", JobHandler)
	http.HandleFunc("/info", InfoHandler)
	http.HandleFunc("/ws", WsHandler)
	http.ListenAndServe("0.0.0.0:8000", nil)
	defer DB.Close()
}
